#include "cudaBase.cuh"
#include "Vector2.h"
#include "MagnetConstVariable.h"
#include <vector>


class CudaForceComputer{

	float *dev_m_Fmagnet_pos;
	float *dev_m_Fmagnet_mm;
	float *dev_m_pos;
	float *dev_m_mm;
	float *dev_m_mindist_pos;
	float *dev_m_mindist_mm;
	float *dev_m_force;
	int *dev_m_ptrFmagnet;	
	float *dev_m_mField;
	float *dev_m_FField;
	float m_gapx, m_gapy;
	int m_numGridx, m_numGridy;
	int m_numMfield;

	float m_k;
	float m_scale;
	int m_numMagnet;
	int m_numParticle;
	int m_numFmagnet;
	int m_numPartition;
	float m_inducefactor;


public:

	CudaForceComputer(int numParticle, int numFmagnet, int numPartition, Vector2 gap, Vector2 numGrid, float inverseU0, float volParticle){

		m_numParticle = numParticle;
		m_numFmagnet = numFmagnet;
		m_numPartition = numPartition;
		m_k = MagnetConst::k;
		
		m_gapx = gap.x();
		m_gapy = gap.y();
		m_numGridx = numGrid.x();
		m_numGridy = numGrid.y();
		m_scale = 5.f;
		m_numMfield = m_numGridx * m_numGridy * m_scale * m_scale;
		m_inducefactor = 3 * 0.999f * inverseU0 * volParticle;


		CUDA_MALLOC(dev_m_Fmagnet_pos, sizeof(Vector2) * numFmagnet);
		CUDA_MALLOC(dev_m_Fmagnet_mm, sizeof(Vector2) * numFmagnet);
		CUDA_MALLOC(dev_m_pos, sizeof(Vector2) * numParticle);
		CUDA_MALLOC(dev_m_mm, sizeof(Vector2) * numParticle);
		CUDA_MALLOC(dev_m_mindist_pos, sizeof(Vector2) * numParticle);
		CUDA_MALLOC(dev_m_mindist_mm, sizeof(Vector2) * numParticle);
		CUDA_MALLOC(dev_m_force, sizeof(Vector2) * numParticle);
		CUDA_MALLOC(dev_m_ptrFmagnet, sizeof(int) * numPartition);
		CUDA_MALLOC(dev_m_mField, sizeof(float) * 2 * m_numMfield);
		CUDA_MALLOC(dev_m_FField, sizeof(float) * 2 * m_numMfield);



	}//CudaForceComputer()


	~CudaForceComputer(){

	
		if (dev_m_Fmagnet_pos) CUDA_FREE(dev_m_Fmagnet_pos);
		if (dev_m_Fmagnet_mm) CUDA_FREE(dev_m_Fmagnet_mm);
		if (dev_m_pos) CUDA_FREE(dev_m_pos);
		if (dev_m_mm) CUDA_FREE(dev_m_mm);
		if (dev_m_mindist_pos) CUDA_FREE(dev_m_mindist_pos);
		if (dev_m_mindist_mm) CUDA_FREE(dev_m_mindist_mm);
		if (dev_m_force) CUDA_FREE(dev_m_mindist_mm);
		if (dev_m_ptrFmagnet) CUDA_FREE(dev_m_ptrFmagnet);
		if (dev_m_mField) CUDA_FREE(dev_m_mField);
		if (dev_m_FField) CUDA_FREE(dev_m_FField);


	}//~CudaForce

	void SendMagnetToDevice(Vector2 *Magnet_pos, Vector2 *Magnet_mm, int numMagnet){

		float *dev_Magnet_pos;
		float *dev_Magnet_mm;
		m_numMagnet = numMagnet;

		CUDA_MALLOC(dev_Magnet_pos, sizeof(Vector2) * numMagnet);
		CUDA_MALLOC(dev_Magnet_mm, sizeof(Vector2) * numMagnet);


		CUDA_MEMCPY(dev_Magnet_pos, Magnet_pos, sizeof(Vector2) * numMagnet, cudaMemcpyHostToDevice);
		CUDA_MEMCPY(dev_Magnet_mm, Magnet_mm, sizeof(Vector2) * numMagnet, cudaMemcpyHostToDevice);

		SetField(dev_Magnet_pos, dev_Magnet_mm);

		CUDA_FREE(dev_Magnet_pos);
		CUDA_FREE(dev_Magnet_mm);



	}//SendMagnetToDevice



	void SendFmagnetToDevice(Vector2 *Fmagnet_pos, Vector2 *Fmagnet_mm, int *ptrFmagnet){

		CUDA_MEMCPY(dev_m_Fmagnet_pos, Fmagnet_pos, sizeof(Vector2) * m_numFmagnet, cudaMemcpyHostToDevice);
		CUDA_MEMCPY(dev_m_Fmagnet_mm, Fmagnet_mm, sizeof(Vector2) * m_numFmagnet, cudaMemcpyHostToDevice);
		CUDA_MEMCPY(dev_m_ptrFmagnet, ptrFmagnet, sizeof(int) * m_numPartition, cudaMemcpyHostToDevice);

	}//SendFmagnetToDevice

	void SendPTCToDevice(Vector2 *pos){//, Vector2 *mm, Vector2 *force) {

		
	
		CUDA_MEMCPY(dev_m_pos, pos, sizeof(Vector2) * m_numParticle, cudaMemcpyHostToDevice);
		CUDA_MEMSET(dev_m_mm, 0, sizeof(Vector2) * m_numParticle);
		CUDA_MEMSET(dev_m_force, 0, sizeof(Vector2) * m_numParticle);
		//CUDA_MEMCPY(dev_m_mm, mm, sizeof(Vector2) * m_numParticle, cudaMemcpyHostToDevice);
		//CUDA_MEMCPY(dev_m_force, force, sizeof(Vector2) * m_numParticle, cudaMemcpyHostToDevice);

	}//SendPTCToDevice

	

	void SendForce(Vector2 *force){

		CUDA_MEMCPY(force, dev_m_force, sizeof(Vector2) * m_numParticle, cudaMemcpyDeviceToHost);

	}//SendForce()

	void SetField(float *dev_Magnet_pos, float *dev_Magnet_mm);
	void ComputeFmagnetForce();
	void ComputePTCvalue();
	void Comdist();
};//class